package com.bigzero.workflow.common.utils;

import com.bigzero.workflow.common.model.TokenInfo;
import com.bigzero.workflow.modules.system.entity.UserEntity;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * jwt工具类
 *
 * @author fanxinxiong
 * @date 2025-02-13 17:40
 **/
@Slf4j
@Data
@Component
public class JwtUtil{

    /**密钥*/
    @Value("${jwt.secret}")
    private String secret;

    /**过期时间*/
    @Value("${jwt.expiration}")
    private long expiration;

    /**
     * 创建token令牌
     * 使用Hs256算法，私钥使用固定密钥
     * @param claims     设置的信息
     * @return
     */
    public String createToken(Map<String, Object> claims){
        //指定加密算法
        SecureDigestAlgorithm<SecretKey, SecretKey> algorithm = Jwts.SIG.HS256;
        //生成JWT的时间
        long expMillis = System.currentTimeMillis() + expiration;
        Date exp = new Date(expMillis);
        //密钥实例
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());

        String compact = Jwts.builder()
                .signWith(key, algorithm) //设置签名使用的签名算法和签名使用的秘钥
                //如果有私有声明，一点要先设置这个自己创建的私有的声明，这个是给builder的claims赋值，一旦卸载标准的声明赋值之后，就是覆盖了那些标准的声明的
                .expiration(exp)
                .claims(claims) //设置自定义负载信息
                .compact();//设置过期时间
        return compact;
    }

     /**
     * 解析token令牌
     * @param token token令牌
     * @return 负载
     */
    public Claims parseToken(String token){
        //密钥实例
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
        Jws<Claims> claimsJws = Jwts.parser()
                .verifyWith(key)  //设置签名的密钥
                .build()
                .parseSignedClaims(token); //设置要解析的jwt
        return claimsJws.getPayload();
    }

    /**
     *  验证token令牌
     * @param token 令牌
     * @return 是否有效
     */
    public boolean validateToken(String token) {
        try{
            //密钥实例
            SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
            Jws<Claims> claimsJws = Jwts.parser().verifyWith(key)  //设置签名的密钥
                    .build().parseSignedClaims(token); //设置要解析的jwt
            claimsJws.getPayload();
            return true;
        }catch(Exception e){
            return false;
        }
    }

    /**
     * 刷新Token
     * @param token 旧的Token令牌
     * @return 新的Token令牌
     */
    public String refreshToken(String token){
        try{
            // 解析旧的Token，获取负载信息
            Claims claims = parseToken(token);
            // 生成新的Token，设置过期时间和签名算法等参数
            return createToken(claims);
        }catch(Exception e){
            throw new RuntimeException("无法刷新令牌！", e);
        }
    }

    /**
     * 解析token令牌
     * @param token token令牌
     * @return TokenInfo  token信息
     */
    public TokenInfo parseTokenInfo(String token){
        TokenInfo tokenInfo = null;
        try{
            Claims claims = parseToken(token);

            String id = Objects.isNull(claims.get("id")) ? "" : claims.get("id").toString();//主键id
            String deptId = Objects.isNull(claims.get("deptId")) ? "" : claims.get("deptId").toString();//部门id
            String username = Objects.isNull(claims.get("username")) ? "" : claims.get("username").toString();//用户名
            String account = Objects.isNull(claims.get("account")) ? "" : claims.get("account").toString();//姓名
            String email = Objects.isNull(claims.get("email")) ? "" : claims.get("email").toString();//邮箱
            String mobile = Objects.isNull(claims.get("mobile")) ? "" : claims.get("mobile").toString();//手机号
            Integer isSys = Objects.isNull(claims.get("isSys")) ? 0 : Integer.parseInt(String.valueOf(claims.get("isSys")));//是否是系统内置,1:是,0:否
            String deptName = Objects.isNull(claims.get("deptName")) ? "" : claims.get("deptName").toString();//部门名称

            tokenInfo = new TokenInfo();
            tokenInfo.setId(id);//主键id
            tokenInfo.setDeptId(deptId);//部门id
            tokenInfo.setUsername(username);//用户名
            tokenInfo.setAccount(account);//姓名
            tokenInfo.setEmail(email);//姓名
            tokenInfo.setMobile(mobile);//手机号
            tokenInfo.setIsSys(isSys);//是否是系统内置,1:是,0:否
            tokenInfo.setDeptName(deptName);//部门名称
        } catch (Exception e) {
            log.error("解析token错误:" + token);
        }
        return tokenInfo;
    }
}
